﻿Namespace Functions
    Public Enum MetisFunctionFieldType
        ''' <summary>Any non-key field</summary>
        ValueField = 0
        ''' <summary>The field is part of the primary key</summary>
        KeyField = 1
    End Enum

    Public Class MetisFunctionField
        Implements IMetisCommonEntity

        Private _OwningFunction As MetisFunction

        Private _ID As Integer
        Private _Name As String
        Private _DBField As DB.DBField
        Private _Annotation As String = ""
        Private _Expression As String = ""
        Private _ReferenceDimension As Dimensions.MetisDimension
        Private _ParentFieldID As Integer = -1

        Private _FieldType As MetisFunctionFieldType = MetisFunctionFieldType.ValueField
        Private _NumberFormat As String = ""
        Private _ColumnWidth As Integer = 64

        Private _CreatedOn As Date
        Private _ModifiedOn As Date



        Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged


        Sub New(ByVal OwningFunction As MetisFunction)
            _OwningFunction = OwningFunction
            _ID = OwningFunction.MetisCore.GetTemporaryFieldID

            Dim tmpFieldCount As Integer = 0
            Do
                tmpFieldCount += 1
                _Name = String.Format(My.Resources.Metis_DimField_NewName, tmpFieldCount)
            Loop Until Not _OwningFunction.Fields.Contains(_Name)

            _DBField = New DB.DBField()
            _DBField.DBfieldName = _Name
            _FieldType = MetisFunctionFieldType.ValueField
        End Sub

        Sub New(ByVal OwningFunction As MetisFunction, ByVal ID As Integer, ByVal FieldName As String, ByVal FieldType As MetisFunctionFieldType, Optional ByVal Expression As String = "")
            _OwningFunction = OwningFunction
            _ID = ID
            _Name = FieldName
            _DBField = New DB.DBField()
            _DBField.DBfieldName = FieldName
            _FieldType = FieldType
        End Sub

        Sub New(ByVal OwningFunction As MetisFunction, ByVal FieldID As Integer, ByVal FieldName As String, ByVal FieldType As MetisFunctionFieldType, _
                ByVal DBFieldName As String, ByVal Expression As String, ByVal Annotation As String, _
                ByVal Dimension As Dimensions.MetisDimension, ByVal ParentFieldID As Integer, _
                ByVal ModifiedOn As Date, ByVal CreatedOn As Date, _
                ByVal NumberFormat As String, ByVal ColWidth As Integer)
            _OwningFunction = OwningFunction
            _ID = FieldID
            _Name = FieldName
            _FieldType = FieldType
            _Expression = Expression
            _ReferenceDimension = Dimension
            _ParentFieldID = ParentFieldID

            Try
                _DBField = _OwningFunction.Table.FieldList(DBFieldName)
            Catch ex As IndexOutOfRangeException
                _DBField = New DB.DBField()
                _DBField.DBfieldName = DBFieldName
            End Try

            _Annotation = Annotation
            _ModifiedOn = ModifiedOn
            _CreatedOn = CreatedOn
            _NumberFormat = NumberFormat
            _ColumnWidth = ColWidth
        End Sub

        Public Function CreateFieldName(Optional ByVal DefaultName As String = "Val") As String
            Dim tmpName As String = DefaultName
            Dim i As Integer = 0
            Do While _OwningFunction.Fields.Contains(tmpName)
                i += 1
                tmpName = String.Format("{0}{1:D2}", DefaultName.Substring(0, Math.Min(DefaultName.Length, Core.MetisCore.MAX_NAME_LENGTH - 2)), i)
            Loop
            Return tmpName
        End Function

        Public Function CreateDBFieldName(Optional ByVal DefaultName As String = "VAL") As String
            Dim tmpName As String = DefaultName
            Dim i As Integer = 0
            Do While _OwningFunction.Fields.ContainsDBField(tmpName)
                i += 1
                tmpName = String.Format("{0}{1:D2}", DefaultName.Substring(0, Math.Min(DefaultName.Length, Core.MetisCore.MAX_DB_NAME_LENGTH - 2)), i)
            Loop
            Return tmpName
        End Function

        Public Function GetNextID() As Integer Implements IMetisCommonEntity.GetNextID
            _ID = _OwningFunction.MetisCore.GetNextFieldID
            RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("ID"))
            Return _ID
        End Function

        Public ReadOnly Property ID() As Integer Implements IMetisCommonEntity.ID
            Get
                Return _ID
            End Get
        End Property

        Public Property Name() As String Implements IMetisCommonEntity.Name
            Get
                Return _Name
            End Get
            Set(ByVal value As String)
                _Name = value

                If MetisCore.IsValidFieldName(value, Core.MetisCore.MAX_NAME_LENGTH) Then
                    For Each item As MetisFunctionField In _OwningFunction.Fields
                        If Not Me.Equals(item) AndAlso value.Equals(item.Name, StringComparison.OrdinalIgnoreCase) Then
                            Throw New Exceptions.DublicateNameException(value)
                        End If
                    Next
                    _Name = value
                    RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Name"))
                Else
                    Throw New Exceptions.InvalidNameException(value)
                End If
            End Set
        End Property

        Public Property PK() As Boolean
            Get
                Return _FieldType = MetisFunctionFieldType.KeyField
            End Get
            Set(ByVal value As Boolean)
                _FieldType = If(value, MetisFunctionFieldType.KeyField, MetisFunctionFieldType.ValueField)
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("PK"))
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("FieldType"))
                If _FieldType = MetisFunctionFieldType.KeyField AndAlso _DBField.DBfieldNullable Then
                    _DBField.DBfieldNullable = False
                    RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldNullable"))
                End If
            End Set
        End Property

        Public Property FieldType() As MetisFunctionFieldType
            Get
                Return _FieldType
            End Get
            Set(ByVal value As MetisFunctionFieldType)
                _FieldType = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("PK"))
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("FieldType"))
                If _FieldType = MetisFunctionFieldType.KeyField AndAlso _DBField.DBfieldNullable Then
                    _DBField.DBfieldNullable = False
                    RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldNullable"))
                End If
            End Set
        End Property

        Public Property Annotation() As String Implements IMetisCommonEntity.Annotation
            Get
                Return _Annotation
            End Get
            Set(ByVal value As String)
                _Annotation = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Annotation"))
            End Set
        End Property

        Public Property Expression() As String
            Get
                Return _Expression
            End Get
            Set(ByVal value As String)
                _Expression = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Expression"))
            End Set
        End Property

        Public Property DimensionID() As Integer
            Get
                Try
                    Return _ReferenceDimension.ID
                Catch ex As Exception
                    Return -1
                End Try

            End Get
            Set(ByVal value As Integer)
                Dimension = _OwningFunction.MetisCore.Dimensions.Find(value)
            End Set
        End Property

        Public Property Dimension() As Dimensions.MetisDimension
            Get
                Return _ReferenceDimension
            End Get
            Set(ByVal value As Dimensions.MetisDimension)
                _ReferenceDimension = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Dimension"))
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DimensionID"))
                If _ReferenceDimension IsNot Nothing Then
                    DBfieldNullable = False
                    DBfieldType = DB.DBFieldType.DBnumber
                    DBfieldLength = 38
                End If
            End Set
        End Property

        Public Property ParentFieldID() As Integer
            Get
                Return _ParentFieldID
            End Get
            Set(ByVal value As Integer)
                Try
                    ParentField = _OwningFunction.Fields.FieldByID(value)
                Catch ex As Exception
                    ParentField = Nothing
                End Try
            End Set
        End Property

        Public Property ParentField() As MetisFunctionField
            Get
                Try
                    Return _OwningFunction.Fields.FieldByID(_ParentFieldID)
                Catch ex As Exception
                    Return Nothing
                End Try
            End Get
            Set(ByVal value As MetisFunctionField)
                _ParentFieldID = If(value IsNot Nothing, value.ID, -1)
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("ParentField"))
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("ParentFieldID"))
                If _ParentFieldID >= 0 Then
                    If value.Dimension IsNot Nothing AndAlso Not value.Dimension.Equals(_ReferenceDimension) Then
                        Dimension = value.Dimension
                    End If
                End If
            End Set
        End Property


        Public Property DBFieldName() As String
            Get
                Return _DBField.DBfieldName
            End Get
            Set(ByVal value As String)
                If MetisCore.IsValidFieldName(value, Core.MetisCore.MAX_DB_NAME_LENGTH) Then
                    For Each item As MetisFunctionField In _OwningFunction.Fields
                        If Not Me.Equals(item) AndAlso value.Equals(item.DBFieldName, StringComparison.OrdinalIgnoreCase) Then
                            Throw New Exceptions.DublicateNameException(value)
                        End If
                    Next
                    _DBField.DBfieldName = value
                    RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBFieldName"))
                Else
                    Throw New Exceptions.InvalidNameException(value)
                End If
            End Set
        End Property

        Public Property DBfieldLength() As Integer
            Get
                Return _DBField.DBfieldLength
            End Get
            Set(ByVal value As Integer)
                _DBField.DBfieldLength = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldLength"))
            End Set
        End Property

        Public Property DBfieldNullable() As Boolean
            Get
                Return _DBField.DBfieldNullable
            End Get
            Set(ByVal value As Boolean)
                _DBField.DBfieldNullable = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldNullable"))
            End Set
        End Property

        Public Property DBfieldTypeAsString() As String
            Get
                Return _DBField.DBfieldTypeAsString
            End Get
            Set(ByVal value As String)
                _DBField.DBfieldTypeAsString = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldType"))
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldTypeAsString"))
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldLength"))
            End Set
        End Property

        Public Property DBfieldType() As DB.DBFieldType
            Get
                Return _DBField.DBfieldType
            End Get
            Set(ByVal value As DB.DBFieldType)
                _DBField.DBfieldType = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldType"))
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldTypeAsString"))
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldLength"))
            End Set
        End Property

        Public Property DBfieldDefault() As String
            Get
                Return _DBField.DBfieldDefault
            End Get
            Set(ByVal value As String)
                _DBField.DBfieldDefault = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("DBfieldDefault"))
            End Set
        End Property

        Public ReadOnly Property DBField() As DB.DBField
            Get
                Return _DBField
            End Get
        End Property

        Public Property NumberFormat() As String
            Get
                Return _NumberFormat
            End Get
            Set(ByVal value As String)
                _NumberFormat = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("NumberFormat"))
            End Set
        End Property

        Public Property ColumnWidth() As String
            Get
                Return _ColumnWidth
            End Get
            Set(ByVal value As String)
                _ColumnWidth = value
                RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("ColumnWidth"))
            End Set
        End Property


        Public ReadOnly Property [Function]() As MetisFunction
            Get
                Return _OwningFunction
            End Get
        End Property

        Public Function Clone() As MetisFunctionField
            Dim tmpField As New MetisFunctionField(_OwningFunction, _ID, _Name, _FieldType, _DBField.DBfieldName, _
                                                   _Expression, _Annotation, _ReferenceDimension, _ParentFieldID, _
                                                   _ModifiedOn, _CreatedOn, _NumberFormat, _ColumnWidth)
            Return tmpField
        End Function

        Public Function CompareTo(ByVal other As IMetisCommonEntity) As Integer Implements System.IComparable(Of IMetisCommonEntity).CompareTo
            Return String.Compare(_Name, other.Name, True)
        End Function

        Public Overrides Function ToString() As String
            Return _Name
        End Function

    End Class
End Namespace

